2024-12-02
December Adventure
I am (trying to) do the December Adventure thing. Not sure yet how much time I will be able to allocate to this but we'll see.
Day 1
Ok, let's start with my plans for this Month.
The last three months I have been low-key writing drawing code I intend to use in certain future projects. I was mostly interested in rendering blocks that are similar in looks to those of window maker, an old X11 desktop which was a more-or-less faithful copy of the NeXTStep desktop. I am not entirely onboard with that kind of window management, but I like the aesthetic of the UI, so I wanted to copy that.
I was not trying to recreate them pixel-per-pixel perfectly, just capture the style. The code is reasonably modular. It can render various "fills" inside a "border". It can approximate the window-maker style within reason, but also the Common Desktop Environment one.
My major plan for this month is putting that code into a library I can use in my other projects. I also have some code I commonly copy-paste between projects - like a Wayland shm buffer pool or some signal handlers - that should probably also find a place in that library. The library would be some kind of proto-toolkit to create simple Wayland clients. I'll have to think about what I should name it…
I would also really like the drawing code to support double-bezel borders (right now it can only do single-bezel borders). Perhaps even make it possible to draw only parts of the border, which would be neat for desktop widgets that are stuck against a screen border. A parser for a theme configuration file would also be very useful, so that a project using the library does not have to do that itself and so that all my programs have a common file to configure their themeing (maybe even supporting realtime theme chages).
My secondary plan is to update some of my existing projects to use that library. Hopefully that will also improve the looks of some of them.
My tertiary plan is to convert my website to org-mode. I am not happy with how maintainable my current website script is and I suspect that would be an upgrade. I already have a prototype, I just need to write some eLisp to auto-generate the chronological blog index and then port my current projects. There are some issues; org-mode can not represent all the formatting I use on this website, but custom blocks and inline HTML will be a reasonable workaround. There will be minor updates to the websites formatting - and I'll be getting a sitemap as well as a keyword index for free! - but overall the structure, looks and feels of my website will not change.
Maybe I'll also do some other things, those will be shared here as well, maybe.
Now, what did I actually do today? Nothing. I was invited by a friend to bake cookies and for any reasonable person that always takes precedence.
Day 2
Today was a boring day project-wise. I spent a lot of time in uni correcting reports for the lab course I tutor, so all I had time for today was finding out how to create a dynamic C library. I did this once before, but with a different build system (meson, currently I prefer make), so I read a fair amount of documentation and created a first proof of concept. I hope to add the first "real" code to it tomorrow.
Day 15
Light rain hits the window of the bus. It is dark outside and the colours of the city blend and blur on the rain smudged glas. In my ears music to match the mood.
I would like to stay here for a while. But eventually I reach my destination and get out.
I skipped a few days. The things I needed to do for uni piled up and my social life got in the way again. But today I got back into it, at least partially.
I wanted something fairly simple, where I didn't need to think too
much, so I worked on my website again. Barely any changes to the
compile.el
script, merely re-defining the function for emitting
center blocks. For some reason the default one emits a <div>
with
the org-center
class; I changed it to emit a simple <center>
element.
I also cleaned up the style sheet. Lots of elements had special cases for rare (or even singular) situations. I removed those and instead introduced special elements for those special situations.
An example of those special situations is the vertical alignment of info-boxen - such as this one - and text when they are placed next to each other - like this. Only the writing index page needs a different style, so it gets a special element.
As a bonus of the simplified elements, I have to use less inline HTML.
#+begin_info-box #+begin_side-by-side For example, this is how I can create an info box with an image side-by-side with text! #+attr_html: :width 100% [[./picture.ping]] #+end_side-by-side #+end_info-box
I am writing this update in my new website repo. The old one is
currently still up; You'll see this article once I finished a few more
minor details, like the nav-section or improving orgs default HTML
output. For some reason it spams <div>
's a lot. But for semantic
HTML reasons I would love to add <section>
elements.
Maybe I'll also bring back the "Next" and "Previously" links I used to have at the bottom, but I am not sure they add much. When reading other peoples websites, I like those the most, on which I can get lost. Mine never achieved that quite yet, perhaps because I keep the navigation a bit to easy, perhaps because I sort the content to well (or not well enough? More subsections?). Not having those two navigation links does a small part in making my website more cozy, maybe. And it's code that is probably tedious to write…
Day 16
Isn't it technically still Day 15 if I am doing this at 00:40 and haven't slept yet? Anyway…
I worked on the org export functionality again. As I have mentioned
before, I was unhappy with the default HTML output. It litters a bunch
of <div>
's everywhere - which break FireFox's reader mode and aren't
very semantic, let alone useful - and the IDs it generated for the
clickable headlines were neither predictable nor stable - they were
effectively random strings.
I fixed that by defining even more translate functions for my derived
HTML export backend. Right now I have functions for template
,
center-block
, section
and headline
.
Speaking of FireFox's reader mode, I also made sure the <article>
element contains only (what I consider to be) the main content of the
page. This helps reader mode hide all the things a user may not wish
to see, like the "Articles from blogs I read"-thing at the end. I did
something similar a few months back were I ensures that certain
elements are hidden when the site is printed. Being accommodating to
your readers is just a nice thing to do.
Day 23
I am a bit tired of working on my website, which is kinda
boring. Hence me not doing a lot the last few days. At least not
enough each day that I feel like sitting down and writing about it. I
mainly finished the navigation section and added a comment mailto link
to it. I will probably skip improving the footnotes styling for now,
since that would require rewriting the inner-template
export
function, which would be a pain, and because I don't actually use
footnotes anymore as they don't fit this medium very well in my
opinion.
I also pushed some minor patches for some of my projects, but they were beither on my december adventure agenda nor were they particularly noteworthy.
I hope I can get to more interesting things soon. Seems like rivers window management protocol is a tiny bit closer every day and I want to play around with that.
Day 24
Today I discovered that my wondeful little bespoke abstraction I
created for my library wrapping river's upcoming window management
protocol - funneling all the various events into a neat
next_event()
function - isn't actually all that great. I came up
with it a few weeks ago in france at a physics conference. The intent
of the library is to be wrapped by other languages, so you can write a
window manager for river in Scheme (everything else would be
silly). Back then I was very convinced this was the correct approach
to make writing bindings the most painless. Now I honestly have no
idea why I thought that. Instead I just converted the library to using
pointers to callback functions. Immediately the code got nicer and
adding new events got simpler.
Anyway, since the rwm branch is a bit farther along now, I managed to
connect to the server, sync and set-up the window management global!
I even got new-window
events! And I am reasonably sure the approch I
am currently using is the most sound for writing a library and a
reasonably featured window manager on top of that.
I decided to re-use the name of my very first C project, which was a window manager for X11: antares. (It's the name of a star). To keep things healthily confusing, that will be the name of the C library, the guile Scheme library wraping the C library and of the reference window manager written using the guile library, which probably will end up featurefull enough to challange the "reference" description.
Day 25
It's still early, but I just managed to position some windows using my
guile Scheme window manager library thing. River is still a bit
crashy, and I have exposed about 0.05
times the theoretically
avaiable functionality in the library, but that is already enough that
one could replicate rivers current default window layout and probably
also the tag system.
I am still not quite sure how much functionality the library will
include over just exposing the raw events and requests. At the very
least, I'll probably abstract away the river-node-v1
objects.
One thing that annoyed me though is that guiles
define-wrapped-pointer-type
creates a record rather than a GOOPS
object. That means I can't use methods. Since methods have dynamic
dispatch, I'd be comfortable calling them things like
f.e. set-geometry
. But functions are not dispatched that way, so to
avoid conflicts, I'll have to use longer names,
f.e. antares-window-set-geometry
.
I could wrap the record in a GOOPS object, but that's not very clean. I could maybe also skip the record and wrap the foreign pointer in directly in a GOOPS object, but I am not sure if that is a good idea…
Day 26
Behold the longest scheme macro I have written in my life so far.
(define-syntax define-binding (syntax-rules () ((_ scheme-name (scheme-args ...) foreign-name (foreign-args ...) (assertions ...) (args ...)) (define scheme-name (let ((foreign-function (foreign-library-function antares foreign-name #:arg-types (list foreign-args ...)))) (lambda (scheme-args ...) assertions ... (foreign-function args ...)))))))
It allows me to easiely create a scheme function wrapping a C function.
(define-binding antares-window-set-visibility (window visibility) "antares_window_set_visibility" ('* int) ((assert (antares-window? window)) (assert (boolean? visibility))) ((unwrap-antares-window window) (if visibility 1 0)))
By the way, if you ever want to debug a macro in guile, you can type
,expand (expression ...)
in the REPL to see what the expression
expands to. Super useful.
Day 27
Added most of the remaining window events and some quality of life for library users (returning error values rather than crashing).
Somewhere is still a bug that triggers an "illegal instruction" crash. I really hope my code causes that, because otherwise this smells like the automagic codegen of guiles FFI doing something funky, which I can't do anything about.
What's missing now to actually get to a state where I can write a useful window manager is to expose the window requests and to implement seats. Eventually I'll also want to do custom border and desktop widget rendering, but only after the window management bits are there and stable and useful.
Day 28
Lot's of crashes in both river and antares. I have reported the river
crashes, but the antares crashes are weird. It's not the library
itself, I tested that. It must be somewhere in the guile library or
guile itself. Sometimes it even is a SIGILL
, which is worrying.
Fun fact: Asan, valgrind and gdb are all useless when you try to debug issues across FFI borders!
AddressSanitizer:DEADLYSIGNAL ================================================================= ==64087==ERROR: AddressSanitizer: SEGV on unknown address (pc 0x7918c3b01052 bp 0x7fffb3b4d250 sp 0x7fffb3b4d218 T0) ==64087==The signal is caused by a READ memory access. ==64087==Hint: this fault was caused by a dereference of a high value address (see register values below). Disassemble the provided pc to learn which register was used. #0 0x7918c3b01052 (<unknown module>) #1 0x7918c56fb595 (/usr/lib/libffi.so.8+0x7595) (BuildId: eecfa567f01d70c2ca4b60a1f7931e5634e41eea) AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV (<unknown module>) ==64087==ABORTING
(gdb) bt #0 0x00007532e2e050c0 in ?? () from /usr/lib/libguile-3.0.so.1 #1 0x00007532e2e05391 in scm_call_n () from /usr/lib/libguile-3.0.so.1 #2 0x00007532e2d7de63 in ?? () from /usr/lib/libguile-3.0.so.1 #3 0x00007532e2acb152 in ffi_closure_unix64_inner (cif=<optimized out>, fun=<optimized out>, user_data=<optimized out>, rvalue=<optimized out>, reg_args=<optimized out>, argp=0x7fff9a2d42f0 "`D-\232\377\177") at ../src/x86/ffi64.c:899 #4 0x00007532e2acb7b8 in ffi_closure_unix64 () at ../src/x86/unix64.S:303 #5 0x00007532dcc1d475 in ?? () from lib/antares.so #6 0x00007fff9a2d4460 in ?? () #7 0x00000f5000000045 in ?? () #8 0x00006547ea6c6b50 in ?? () #9 0x00006547ea6c2790 in ?? () #10 0x00006547ea6c2790 in ?? () #11 0x00006547ea6c2790 in ?? () #12 0x00007fff9a2d4330 in ?? () #13 0x00007532e2acb596 in ffi_call_unix64 () at ../src/x86/unix64.S:104 #14 0x0000000000000000 in ?? ()
(I'll spare you valgrinds output because it says even less while being more verbose.)
Anyway, I've asked for debugging tips in the relevant channels and until I get a response will go over my code again to see if I maybe missed something…
A shame really, because I was just getting into writing some actual window management logic and doing that in scheme felt great!
Ok it's a few hours later now and I've got it: The garbage collector lost track of the callback functions and sweeped them. Defining them as toplevel variables rather than inline lambdas fixed the issue.
And now I have connected a REPL to a running instance of the window manager! Once this is actually usable, it will be insanely cool.